#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include "param.h"
#include "types.h"
#include "defs.h"

extern filebuf_ring io_ring;

void
swap (filebuf **a, filebuf **b) {
    filebuf *tmp;
    tmp = *a;
    *a = *b;
    *b = tmp;
}

int
heap_shift_down (filebuf_heap *heap, int i) {
    int j;
    #define curr_buf(x) (heap->bufs[x]->b_out)
    #define elem(x) (curr_buf(x)->data[curr_buf(x)->curr])
    do {
        j = i * 2 + 1;
        if (j >= heap->num) break;
        if (j+1 < heap->num) {
            if (elem(j) < elem(j+1)) {
                j++;
            }
        }
        if (elem(i) < elem(j)) {
            swap (&(heap->bufs[i]), &(heap->bufs[j]));
            i = j;
        } else {
            break;
        }
    } while (j < heap->num);
    return 0;
}

int
heap_make (filebuf_heap *heap) {
    int i;
    for (i = heap->num / 2; i >= 0; i--) {
        heap_shift_down (heap, i);
    }
    return 0;
}

int
heap_shrink (filebuf_heap *heap) {
    if (heap->bufs[0]->status == FB_S_READY)
        printf ("heap_shrink: unexpected READY->FIN.\n");
    heap->bufs[0]->status = FB_S_FIN;
    swap (&(heap->bufs[0]), &(heap->bufs[heap->num-1]));
    heap->num--;
    return 0;
}

int
heap_init (filebuf_heap *heap, filebuf **bufs, int n) {
    int i;
    heap->bufs = bufs;
    heap->num = n;
    for (i = 0; i < n; i++) {
        /* 等待所有缓冲区准备完毕 */
        printf ("HEAP: Waiting for resource %d unlock.\n", i);
        fflush (stdout);
        WAIT (bufs[i]->ex_res);
        printf ("HEAP: Resource %d unlocked.\n", i);
        fflush (stdout);
    }
    heap_make (heap);
    return 0;
}

/* 读到最后一个时会返回-1 */
int
heap_get_min (filebuf_heap *heap, threadinfo *info, uint64 *b) {
    *b = elem(0);
    curr_buf(0)->curr++;
    /* 准备下一个数据 */
    if (curr_buf(0)->curr >= curr_buf(0)->elem_num) {
        switch (heap->bufs[0]->status) {
        case FB_S_READY: {
            filebuf_trans_out2in (heap->bufs[0]);
            filebuf_ring_put (&io_ring, heap->bufs[0]);
            info->status = TI_S_LOADING;
            WAIT (heap->bufs[0]->ex_res);
            /* READY->IFIN */
            if (heap->bufs[0]->b_out == NULL) {
                /* 已读完 */
                if (heap->num > 1)
                    heap_shrink (heap);
                else
                    goto finish;
            }
            break;
        }
        case FB_S_IFIN: {
            filebuf_trans_out2un (heap->bufs[0]);
            /* IFIN->FIN */
            if (heap->bufs[0]->b_out == NULL) {
                if (heap->num > 1)
                    heap_shrink (heap);
                else
                    goto finish;
            }
            break;
        }
        case FB_S_FIN: {
            goto finish;
            break;
        }
        default : {
            HANDLE_ERROR ("heap_get_min","heap->bufs[0]->status",0);
            break;
        }
        }
    }
    if (curr_buf(0)->curr >= curr_buf(0)->elem_num)
        HANDLE_ERROR ("heap_get_min","curr >= elem_num",0);
    heap_shift_down (heap, 0);
    return 0;
    finish:
    if (heap->bufs[0]->status != FB_S_IFIN)
        printf ("heap_get_min: unexpected ?->FIN.\n");
    heap->bufs[0]->status = FB_S_FIN;
    return -1;
    error:
    return -1;
}



#undef curr_buf
#undef elem